﻿using System;
using BizElements.Core;

namespace BizElements.BusinessLayer
{
    /// <summary>
    /// Specifies an actor (eg. a person or another system) and it's permissions to work with the current system.
    /// </summary>
    public interface IActor
    {
        #region IActor.

        /// <summary>
        /// Gets the value, tipically an integer or a string, which identifies the current actor and it's 
        /// <b>position</b> in the system/organization.
        /// </summary>
        /// <remarks>Required to implement horizontal security. Data model must link actors and data they can access.</remarks>
        object Id { get; }

        /// <summary>
        /// Gets the name the actor used to gain access to the system.
        /// </summary>
        /// <remarks>May be used to implement horizontal security. However, <see cref="Id"/> should be prefered
        /// since in many systems username may be changed.</remarks>
        string Name { get; }

        /// <summary>
        /// Determines whether the current actor has permission to initiate the specified action.
        /// </summary>
        /// <param name="actionId">The ID of the action that the actor is trying to initiate. Implementations should 
        /// return <b>false</b> if the given ID is of the wrong type (eg. <b>string</b> instead of <b>int</b>.</param>
        /// <returns><b>True</b> it the current actor has permission to initiate the specified action; <b>false</b> otherwise.</returns>
        /// <remarks>Required to implement vertical security. Vertical security checks should be processed before,
        /// often more complex, horizontal security.</remarks>
        bool HasPermission(object actionId);

        /// <summary>
        /// Determines whether the current actor belongs to the specified unit.
        /// </summary>
        /// <param name="unit">The unit for which to check membership. Implementations should return <b>false</b> 
        /// if the given value is of the wrong type (eg. <b>string</b> instead of <b>int</b>.</param>
        /// <returns><b>True</b> it the current actor is a member of the specified unit; <b>false</b> otherwise.</returns>
        /// <remarks>Often used to enforce horizontal security. Sometimes all actors of a unit have the permission 
        /// to work on the same set of data.</remarks>
        bool IsInUnit(object unit);

        /// <summary>
        /// Gets the ID of the actor's primary unit. Tipically an integer, GUID or a string; <b>null</b> if primary unit is not defined for the current actor.
        /// </summary>
        /// <remarks><para>Even though not typical, actor may belong to more than unit. This property specifies which of 
        /// them is considered to be primary.</para>
        /// <para>Often used to enforce horizontal security. Sometimes all actors of a unit have the permission 
        /// to work on the same set of data.</para></remarks>
        object PrimaryUnit { get; }

        /// <summary>Gets an array of IDs of all units that actor is associated with. In most organization and system an actor can belong to only one unit 
        /// (<see cref="PrimaryUnit"/>) but it is possible that in some special cases you may design a system where actor can belong to multiple units.</summary>
        object[] AllUnits { get; }

        /// <summary>Gets the collection of customized information associated with the actor, such as full name, business unit name and similar.</summary>
        /// <value>A IPropertyCollection with all custom information.</value>
        IPropertyCollection<string> ExtendedProperties { get; }

        /// <summary>
        /// Gets the ID of the organization to which the actor belongs. Required for multi-tenant installations. Tipically an integer or GUID.
        /// </summary>
        object Organization { get; }

        /// <summary>Optional ID of actor's currently active session.</summary>
        object SessionId { get; }

        #endregion
    }
}
